﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GbmpGroupComponent.h"
#include "IElement.h"
#include "DbObjectUtils.h"
#include "INdbCopyStrategyReporter.h"
#include "IGroup.h"
#include "IGroupType.h"
#include "IElementBasicInformation.h"
#include "GbmpGroupManager.h"
#include "IDocument.h"
#include "NdbUpgrade.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

CREATE_DEBUG_MODE(EnableAcceptUpdateForUnsyncElements, L"不同步Elements接受同步Element的更新", gcmp::DebugModeGroup::DMGT_OTHERS, L"GDMPLab", L"2023-12-20", L"开启此mode，不同步Elements可接受同步Element的更新。");


BEGIN_UPGRADE_CLASS(gcmp, GbmpGroupComponent, 2)
ADD_NON_OBJECT_PROPERTY(OwnerPtr<IGroupComponent>, DefaultGroupComponent)
END_UPGRADE_CLASS

DBOBJECT_DATA_DEFINE(GbmpGroupComponent)
{
    m_pOwnerElement = nullptr;
    SetDefaultGroupComponent__(IGroupComponent::CreateDefaultGroupComponentForGroup());
}

bool gcmp::GbmpGroupComponent::SetOwnerElement(IElement* pOwnerElement)
{
    m_pOwnerElement = pOwnerElement;
    IGroupComponent* pDefaultGroupComponent = GetDefaultGroupComponentFW__().get();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDefaultGroupComponent, L"pDefaultGroupComponent为空",L"GDMPLab",L"2024-03-30");
    pDefaultGroupComponent->SetOwnerElement(pOwnerElement);

    return true;
}

NdbObject* gcmp::GbmpGroupComponent::GetTopOwnerObject() const
{
    return nullptr;
}

void gcmp::GbmpGroupComponent::NdbCopyReport(const IElement* pSrcElement, INdbCopyStrategyReporter* pReporter) const
{
    if (!pSrcElement || !pReporter)
        return;

    const IGroupComponent* pDefaultGroupComponent = GetDefaultGroupComponent__().get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDefaultGroupComponent, L"pDefaultGroupComponent为空",L"GDMPLab",L"2024-03-30");
    return pDefaultGroupComponent->NdbCopyReport(pSrcElement, pReporter);
}

bool gcmp::GbmpGroupComponent::IsSync(const ElementId& elementIdInGroup) const
{
    const IGroup* pOwner = quick_cast<const IGroup>(GetOwnerElement());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pOwner, L"pOwner为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = pOwner->GetDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    return GroupManager::GetInstance(pDoc).IsSync(pOwner->GetElementId(), elementIdInGroup);
}

bool gcmp::GbmpGroupComponent::AcceptSync(GroupEditType type, const ElementId& elementIdInType) const
{
    const IGroup* pOwner = quick_cast<const IGroup>(GetOwnerElement());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pOwner, L"pOwner为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = pOwner->GetDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    // TODO 现在逻辑比较简单，后面如果需要可以考虑一下几何关系
    if (type == GroupEditType::AddElement || type == GroupEditType::RestoreReferenceElement)
    {
        return true;
    }

    if (DEBUG_MODE(EnableAcceptUpdateForUnsyncElements))
    {
        // 打开此DebugMode，不同步Element也可接受同步Element的更新
        return true;
    }
    else
    {
        const std::map<ElementId, ElementId>& typeToGroupIdMap = pOwner->GetTypeToGroupIdMap();
        const std::map<ElementId, ElementId>& referenceTypeToGroupIdMap = pOwner->GetReferenceTypeToGroupIdMap();
        auto iter = typeToGroupIdMap.find(elementIdInType);
        auto refItem = referenceTypeToGroupIdMap.find(elementIdInType);
        if (iter != typeToGroupIdMap.cend())
        {
            const IElement* pElement = pDoc->GetElement(pOwner->GetGroupId());
            if (const IGroup* pParentGroup = quick_cast<IGroup>(pElement))
            {
                const std::map<ElementId, ElementId>&  refMap = pParentGroup->GetReferenceGroupToTypeIdMap();
                // 不同步的对象只能走ReferenceElement更新
                if (refMap.find(iter->second) != refMap.end())
                    return false;
            }
            else if (const IGroupType* pParentType = quick_cast<IGroupType>(pElement))
            {
                const std::set<ElementId>& refElementIds = pParentType->GetReferenceElementIdsInGroupType();
                // 不同步的对象只能走ReferenceElement更新
                if (refElementIds.count(iter->second) == 1)
                    return false;
            }
            return GroupManager::GetInstance(pDoc).IsSync(pOwner->GetElementId(), iter->second);
        }
        else if (refItem != referenceTypeToGroupIdMap.cend())
        {
            return GroupManager::GetInstance(pDoc).IsSync(pOwner->GetElementId(), refItem->second);
        }
    }
    

    return false;
}

bool gcmp::GbmpGroupComponent::CanAddReferenceElement(const ElementId& elementIdInType) const
{
    const IGroup* pOwner = quick_cast<const IGroup>(GetOwnerElement());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pOwner, L"pOwner为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = pOwner->GetDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    const std::map<ElementId, ElementId>& typeToGroupIdMap = pOwner->GetTypeToGroupIdMap();

    const IElement* pElementInType = pDoc->GetElement(elementIdInType);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElementInType, L"pElementInType为空",L"GDMPLab",L"2024-03-30");
    auto itemInGroup = typeToGroupIdMap.find(pElementInType->GetGroupId());
    if (itemInGroup == typeToGroupIdMap.cend())
        return false;

    return GroupManager::GetInstance(pDoc).IsSync(pOwner->GetElementId(), itemInGroup->second);
}
